/*
  Losu Copyright Notice
  --------------------
    Losu is an open source programming language project under the MIT license
  that can be used for both academic and commercial purposes. There are no
  fees, no royalties, and no GNU-like "copyright" restrictions. Losu qualifies
  as open source software. However, Losu is not public property, and founder
  'chen-chaochen' retains its copyright.

    Losu has been registered with the National Copyright Administration of the
  People's Republic of China, and adopts the MIT license as the copyright
  licensing contract under which the right holder conditionally licenses its
  reproduction, distribution, and modification rights to an unspecified public.

    If you use Losu, please follow the public MIT agreement or choose to enter
  into a dedicated license agreement with us.

  The MIT LICENSE is as follows
  --------------------
  Copyright  2020 - now  chen-chaochen

    Permission is hereby granted, free of charge, to any person obtaining a
  copy of this software and associated documentation files (the “Software”), to
  deal in the Software without restriction, including without limitation the
  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  sell copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  SOFTWARE.
*/

/*
  This file was generated by losuh - Losu Header Generator, which is part of
  the Losu SDK.

  Losu is an open source programming language from China with excellent
  performance (comparable to lua), ultra-lightweight resource footprint (only
  4KB RAM) and easy-to-learn syntax (similar to Python) for IoT development.

  This file follows the following MIT LICENSE by default
  ------------------------------------
  Copyright  2020 - now  chen-chaochen

    Permission is hereby granted, free of charge, to any person obtaining a
  copy of this software and associated documentation files (the “Software”), to
  deal in the Software without restriction, including without limitation the
  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  sell copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  SOFTWARE.

*/

#include "cstring.lsh.h"
#include "losu_malloc.h"
#include <string.h>

static uint8_t __utf8CheckLen (uint8_t c);

/**
 * @fn strlen(s:str) -> int
 * @brief 返回字符串的 C 风格长度
 */
int32_t
__losuh__func_strlen_cstring_cstring (LosuVm *vm)
{
  const char *s = arg_getstr (vm, 1);
  arg_returnnum (vm, (_l_number)strlen (s));
  return 1;
}
/**
 * @fn strstr(fs:str, ss:str) -> str
 * @brief 返回在 fs 中以 ss 开头的字符串
 */
int32_t
__losuh__func_strstr_cstring_cstring (LosuVm *vm)
{
  const char *fs = arg_getstr (vm, 1);
  const char *ss = arg_getstr (vm, 2);
  arg_returnstr (vm, strstr (fs, ss));
  return 1;
}
/**
 * @fn strtok(s:str, sep:str) -> str
 * @brief 返回在 s 中以 sep 分隔的字符串
 */
int32_t
__losuh__func_strtok_cstring_cstring (LosuVm *vm)
{
  LosuObj *s = arg_get (vm, 1);
  LosuObj *sep = arg_get (vm, 2);
  const char *r = NULL;
  if (obj_type (vm, s) == LosuTypeDefine_null)
    r = strtok (NULL, obj_tostr (vm, sep));
  else
    r = strtok ((char *)obj_tostr (vm, s), obj_tostr (vm, sep));
  if (r == NULL)
    return 0;
  arg_returnstr (vm, r);
  return 1;
}
/**
 * @fn strmid(s:str, start:int, end:int) -> str
 * @brief 返回 s 中从 start 到 end 的子字符串
 */
int32_t
__losuh__func_strmid_cstring_cstring (LosuVm *vm)
{
  const char *s = arg_getstr (vm, 1);
  int32_t start = arg_getnum (vm, 2);
  int32_t end = arg_getnum (vm, 3);
  LosuObj o = obj_newstrlen (vm, (char *)s + start, end - start + 1);
  arg_return (vm, o);
  return 1;
}
/**
 * @fn strrev(s:str) -> str
 * @brief 返回 s 的反转字符串
 */
int32_t
__losuh__func_strrev_cstring_cstring (LosuVm *vm)
{
  const char *s = arg_getstr (vm, 1);
  size_t len = strlen (s);
  size_t count = len - 1;
  char *r = __losu_mem_malloc (vm, len + 1);
  memset (r, 0, len + 1);

  for (size_t i = 0; i < len;)
    {
      uint8_t clen = __utf8CheckLen (s[i]);
      switch (clen)
        {
        case 1:
          r[count] = s[i];
          break;
        case 2:
          r[count - 1] = s[i];
          r[count] = s[i + 1];
          break;
        case 3:
          r[count - 2] = s[i];
          r[count - 1] = s[i + 1];
          r[count] = s[i + 2];
          break;
        case 4:
          r[count - 3] = s[i];
          r[count - 2] = s[i + 1];
          r[count - 1] = s[i + 2];
          r[count] = s[i + 3];
          break;
        default:
          break;
        }
      i += clen;
      count -= clen;
    }
  arg_returnstr (vm, r);
  __losu_mem_free (vm, r);
  return 1;
}
/**
 * @fn strupper(s:str) -> str
 * @brief 返回 s 的大写字符串
 */
int32_t
__losuh__func_strupper_cstring_cstring (LosuVm *vm)
{
  const char *s = arg_getstr (vm, 1);
  size_t len = strlen (s);
  char *r = __losu_mem_malloc (vm, len + 1);
  memset (r, 0, len + 1);
  for (size_t i = 0; i < len; i++)
    {
      if (s[i] >= 'a' && s[i] <= 'z')
        r[i] = s[i] - 32;
      else
        r[i] = s[i];
    }
  arg_returnstr (vm, r);
  __losu_mem_free (vm, r);
  return 1;
}
/**
 * @fn strlower(s:str) -> str
 * @brief 返回 s 的小写字符串
 */
int32_t
__losuh__func_strlower_cstring_cstring (LosuVm *vm)
{
  const char *s = arg_getstr (vm, 1);
  size_t len = strlen (s);
  char *r = __losu_mem_malloc (vm, len + 1);
  memset (r, 0, len + 1);
  for (size_t i = 0; i < len; i++)
    {
      if (s[i] >= 'A' && s[i] <= 'Z')
        r[i] = s[i] + 32;
      else
        r[i] = s[i];
    }
  arg_returnstr (vm, r);
  __losu_mem_free (vm, r);
  return 1;
}
/**
 * @fn strcpy(...:str ) -> str
 * @brief 返回连接所有参数的字符串
 */
int32_t
__losuh__func_strcpy_cstring_cstring (LosuVm *vm)
{
  int32_t args = arg_num (vm);
  size_t len = 0;
  const char **slist = __losu_mem_malloc (vm, args * sizeof (char *));
  for (int32_t i = 1; i <= args; i++)
    {
      slist[i - 1] = arg_getstr (vm, i);
      len += strlen (slist[i - 1]);
    }
  char *r = __losu_mem_malloc (vm, len + 1);
  memset (r, 0, len + 1);
  for (int32_t i = 0; i < args; i++)
    strcat (r, slist[i]);
  arg_returnstr (vm, r);
  __losu_mem_free (vm, r);
  return 1;
}

/**
 * @fn strcount(s:str, ss:str) -> int
 * @brief 返回 s 中 ss 字符串出现的次数
 */
int32_t
__losuh__func_strcount_cstring_cstring (LosuVm *vm)
{
  const char *s1 = arg_getstr (vm, 1);
  const char *s2 = arg_getstr (vm, 2);
  size_t len1 = strlen (s1);
  size_t len2 = strlen (s2);
  int32_t count = 0;
  int32_t ans = 0;

  for (int32_t i = 0; i < len1; i++)
    {
      if (s1[i] == s2[0])
        {
          count = 0;
          for (int32_t j = i; j < i + len2; j++)
            {
              if (s1[j] != s2[j - i])
                break;
              else
                count++;
              if (count == len2)
                ans++;
            }
        }
    }
  arg_returnnum (vm, ans);
  return 1;
}
/**
 * @fn strcmp(s1:str, s2:str, len:int) -> int
 * @brief 返回 s1 和 s2 的比较结果, 不指定 len 则比较整个字符串
 */
int32_t
__losuh__func_strcmp_cstring_cstring (LosuVm *vm)
{
  const char *s1 = arg_getstr (vm, 1);
  const char *s2 = arg_getstr (vm, 2);
  LosuObj *lenobj = arg_get (vm, 3);
  int32_t r = 0;
  if (obj_type (vm, lenobj) == LosuTypeDefine_null)
    r = strcmp (s1, s2);
  else
    r = strncmp (s1, s2, (size_t)obj_tonum (vm, lenobj));
  r = r < 0 ? -1 : (r > 0 ? 1 : 0);
  arg_returnnum (vm, r);
  return 1;
}
/**
 * @fn strnew(s:str, n:int) -> str
 * @brief 将 n 个 s 连接起来
 */
int32_t
__losuh__func_strnew_cstring_cstring (LosuVm *vm)
{
  const char *s = arg_getstr (vm, 1);
  int32_t n = arg_getnum (vm, 2);
  size_t len = strlen (s);
  char *r = __losu_mem_malloc (vm, len * n + 1);
  memset (r, 0, len * n + 1);
  for (int32_t i = 0; i < n; i++)
    strcat (r, s);
  arg_returnstr (vm, r);
  __losu_mem_free (vm, r);
  return 1;
}

static uint8_t
__utf8CheckLen (uint8_t c)
{
  /** 单字节序列的 leader byte 总是在（0-127）范围内。
   * 两字节序列的 leader byte 在（194-223）范围内。
   * 三字节序列的 leader byte 在（224-239）范围内。
   * 四字节序列的 leader byte 在（240-247）范围内。
   * */
  uint8_t len = 0;
  if (c < 0x80)
    { /* then UTF-8   单字节 */
      len = 1;
    }
  else if (c >= 0xC2 && c <= 0xDF)
    { /* then 首字节   UTF-8 占用2个字节 */
      len = 2;
    }
  else if (c >= 0xE0 && c <= 0xEF)
    { /* then 首字节   UTF-8 占用3个字节 */
      len = 3;
    }
  else if (c >= 0xF0 && c <= 0xF7)
    { /* then 首字节   UTF-8 占用4个字节 */
      len = 4;
    }

  return len;
}